import os  # 用于访问环境变量和操作系统功能

from langchain_community.chat_message_histories import ChatMessageHistory  # 引入历史聊天对象
from langchain_core.messages import HumanMessage
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder  # 用于构建对话提示模板
from langchain_core.runnables import RunnableWithMessageHistory
from langchain_openai import ChatOpenAI  # 用于调用OpenAI兼容接口的模型（适配阿里云百炼）
from pydantic import SecretStr  # 用于安全存储和传递API密钥（避免明文暴露）

api_key = os.getenv("AI_API_KEY")
# 检查API密钥是否存在，若不存在则抛出错误提示
if not api_key:
    raise ValueError("请设置环境变量DASHSCOPE_API_KEY（阿里云百炼API-KEY）")
# 1. 创建大语言模型实例（适配阿里云百炼的DeepSeek模型）
model = ChatOpenAI(
    model="deepseek-r1",  # 模型名称，需与阿里云百炼平台支持的模型名一致
    temperature=0,  # 生成内容的随机性（0表示确定性输出，1表示最大随机性）
    max_tokens=None,  # 最大生成 tokens 数（None表示使用模型默认值）
    timeout=None,  # 超时时间（None表示无超时限制）
    max_retries=2,  # 调用失败时的最大重试次数
    api_key=SecretStr(api_key),  # 以安全字符串形式传递API密钥
    base_url="https://dashscope.aliyuncs.com/compatible-mode/v1",  # 阿里云百炼的OpenAI兼容接口地址
)

# 2. 创建提示模板（定义对话角色和用户输入格式）
prompt_template = ChatPromptTemplate.from_messages([
    ("system", "你是一个资深Python开发工程师"),  # 系统提示：定义模型的角色和行为
    MessagesPlaceholder(variable_name='chat_key')  # 传输历史聊天记录
])

# 3. 构建完整的处理链路（提示模板→模型）
chain = prompt_template | model  # 管道操作：按顺序执行提示模板→模型调用

# 4. 保存聊天历史记录
store = {}  # 所有用户的聊天记录都保存到store里面。 key:sessionID -> value : 历史聊天记录对象


# 通过session_id获取对应聊天记录
def get_session_history(session_id: str):
    if session_id not in store:
        store[session_id] = ChatMessageHistory()
    return store[session_id]


# 用来发送消息
do_message = RunnableWithMessageHistory(
    chain,
    get_session_history,
    input_messages_key='chat_key'  # 每次聊天发送消息的key
)
# 定义invoke发送消息配置
chatConfig = {'configurable': {'session_id': 'zs123'}}  # 给会话定义一个session_id

# # 第一轮:阻塞式
# res1 = do_message.invoke(
#     {
#         'chat_key': [HumanMessage(content="我有三个包吃现在吃了一个，还有几个？")]
#     },
#     config=chatConfig
# )
# print(res1.content)
#
# # 第一轮:阻塞式
# res2 = do_message.invoke(
#     {
#         'chat_key': [HumanMessage(content="我又吃了两个包子，还有几个?")]
#     },
#     config=chatConfig
# )
# print(res2.content)

# 第三轮:流式
for resp in do_message.stream(
        {'chat_key': [HumanMessage(content="介绍一下python的好处")]},
        config=chatConfig
):
    # 一次响应就是一个token
    print(resp.content,end='')
